package com.cxyd.modules.wcs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cxyd.common.constant.RcsConstants;
import com.cxyd.common.constant.WcsConstants;
import com.cxyd.common.service.impl.CrudServiceImpl;
import com.cxyd.modules.api.dto.RcsResultHK;
import com.cxyd.modules.log.service.SysLogWorkService;
import com.cxyd.modules.wcs.dao.AgvCallbackHkDao;
import com.cxyd.modules.wcs.dao.AgvTrkHkDao;
import com.cxyd.modules.wcs.dao.AgvTrkYfDao;
import com.cxyd.modules.wcs.dto.AgvCallbackHkDTO;
import com.cxyd.modules.wcs.entity.*;
import com.cxyd.modules.wcs.service.*;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

@Service
public class AgvCallbackHkServiceImpl extends CrudServiceImpl<AgvCallbackHkDao, AgvCallbackHkEntity, AgvCallbackHkDTO> implements AgvCallbackHkService {
    @Resource
    private AgvTrkHkService hkService;
    @Resource
    private TrkService trkService;
    @Resource
    private PcItemService pcItemService;
    @Resource
    private StnMappingService stnMappingService;
    @Resource
    private SysLogWorkService logWorkService;
    @Resource
    private RouteSetService routeSetService;
    @Resource
    private AgvTrkHkDao agvTrkHkDao;

    @Override
    public QueryWrapper<AgvCallbackHkEntity> getWrapper(Map<String, Object> params) {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RcsResultHK callbackHandle(AgvCallbackHkDTO dto) {
        String reqCode = dto.getReqCode();
        String taskCode = dto.getTaskCode();
        String robotCode = dto.getRobotCode();
        String method = dto.getMethod();
//        当前站点信息
        String positionCode = dto.getCurrentPositionCode();
//        根据taskCode获取任务信息
        AgvTrkHkEntity task = hkService.getAgvTrkByTaskCode(taskCode);
        if (task == null) {
//            任务不存在不处理即可
            return new RcsResultHK().success(reqCode);
        }
//        记录车号
        task.setAgvCode(robotCode);
//        记录当前站点
        task.setCurrentPositionCode(positionCode);
//        不同的method调用不同的处理逻辑
        /**
         * 任务当前状态0-初始
         * 1-任务下发
         * 2-任务开始
         * 3-搬送中
         * 31-取料申请
         * 32-放料申请
         * 33-取料完成
         * 34-放料完成
         * 35-申请打包
         * 4-任务完成
         * 9-任务取消
         */
        if (RcsConstants.HK_METHOD_START.equals(method)) {
            //1.任务开始(更新)
            agvTrkStart(task);
        } else if (RcsConstants.HK_METHOD_OUTBIN.equals(method)) {
//            2.走出储位(可认为是下架)
            agvTrkOutbin(task, positionCode);
        } else if (RcsConstants.HK_METHOD_LOAD_REQ.equals(method)) {
//            3.AGV-LOAD申请(请求上料)
            agvTrkApplyLoad(task, positionCode);
        } else if (RcsConstants.HK_METHOD_LOAD_DONE.equals(method)) {
//            3.AGV-LOAD申请(取料完成)
            agvTrkLoadDone(task, positionCode);
        } else if (RcsConstants.HK_METHOD_UNLOAD.equals(method)) {
//            5.AGV-到达安全交互外侧位置
            agvTrkUnload(task, positionCode);
        } else if (RcsConstants.HK_METHOD_UNLOAD_DONE.equals(method)) {
//            6.AGV-下料完成（放下料架）
//            agvTrkUnLoadDone(task, positionCode);
        } else if (RcsConstants.HK_METHOD_PACKAGE_REQ.equals(method)) {
//            7.AGV-到达打包区申请打包
            agvTrkApplyPackage(task, positionCode);
        } else if (RcsConstants.HK_METHOD_PACKAGE_WAIT.equals(method)) {
//            8.AGV-打包等待
//            agvTrkApplyPackageWait(task, positionCode);
        } else if (RcsConstants.HK_METHOD_END.equals(method)) {
//            7.AGV-顶起料架后申请离开
            agvTrkEnd(task, positionCode);
        } else {

        }
        return new RcsResultHK().success(reqCode);
    }

    /***
     * 任务开始(步骤1)
     * @param task
     */
    private void agvTrkStart(AgvTrkHkEntity task) {
        String workName = "[流程-开始搬运]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkStart";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "任务单[" + task.getTaskCode() + "]收到[start]通知,小车[" + task.getAgvCode() + "]开始作业!";
//        start时并未执行该任务,只是说CTU接到有任务而已
        task.setStatus(RcsConstants.HK_STATUS_START);
        task.setData("start");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        找到对应[wcs_trk]任务进行更新
        TrkEntity trkEntity = trkService.selectById(task.getTrkId());
        if (trkEntity != null) {
            trkEntity.setComments(msg);
            trkEntity.setUpdater(WcsConstants.WCS_USER_ID);
            trkEntity.setUpdateDate(new Date());
            trkService.updateById(trkEntity);
        }
//        以料箱维度记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 走出储位（一般为出库下架）
     * @param task
     */
    private void agvTrkOutbin(AgvTrkHkEntity task, String positionCode) {
//        通知wms料箱已下架等
        String workName = "[流程-下料通知]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkOutbin";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "小车[" + task.getAgvCode() + "]将站点[" + positionCode + "]料架取出!";
//        更新站点状态(同时需要告知PLC空箱被取走-信号点变2)
        StnMappingEntity curStn = stnMappingService.getStnByNo(positionCode);
        if (curStn == null) {
            //            站点未配置
            code = "Outbin_err_001";
            msg = msg + "当前站点[" + positionCode + "]未在[wcs_stn_mapping]配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        curStn.setStatus(0);
        curStn.setContNo("");
        curStn.setComments("小车取出空箱!");
        curStn.setUpdateDate(new Date());
//        更新PLC货架状态(空箱被取走,更新信号=2)
        pcItemService.updateValueByNo(curStn.getTargetAgv(), "2");

        stnMappingService.updateById(curStn);
//        更新任务状态
        task.setStatus(RcsConstants.HK_STATUS_TAKE); //任务状态
        task.setData("叉车已取出料架!");
        task.setUpdateDate(new Date());
        hkService.updateById(task);

        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * AGV-LOAD申请(取料)
     * @param task
     */
    private void agvTrkApplyLoad(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-申请取料]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyLoad";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[LoadRequest]申请!";

        //        匹配主任务
        TrkEntity wcsTrk = trkService.selectById(task.getTrkId());
        if (wcsTrk == null) {
//            站点未配置
            code = "LoadError_002";
            msg = msg + "无关联主任务!ID为[" + task.getTrkId() + "]!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }

//        获取工位外侧等待点X
        StnMappingEntity extStn = stnMappingService.getStnByNo(positionCode);
        if (extStn == null) {
            code = "LoadError_001";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        向PLC申请进入
        pcItemService.updateValueByNo(extStn.getTargetAgv(), "1");
        msg = msg + "取料申请[" + extStn.getTargetAgv() + "]写入信号[1]!";
        wcsTrk.setComments(msg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
//        更新任务状态
        task.setStatus(RcsConstants.HK_STATUS_LOAD); //任务状态
        task.setData("LoadRequest");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /**
     * 取料完成
     */
    private void agvTrkLoadDone(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-取料完成]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkLoadDone";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[LoadDone]申请!";

        //        匹配主任务
        TrkEntity wcsTrk = trkService.selectById(task.getTrkId());
        if (wcsTrk == null) {
//            站点未配置
            code = "LoadDone_001";
            msg = msg + "无关联主任务!ID为[" + task.getTrkId() + "]!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        获取当前取料工位
        StnMappingEntity curStn = stnMappingService.getStnByNo(positionCode);
        StnMappingEntity frmPosStn = stnMappingService.getStnByNo(wcsTrk.getFrmPos());
        if (curStn == null) {
            code = "LoadDone_002";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        释放工位状态信息
        frmPosStn.setStatus(0);
        frmPosStn.setContNo("");
        frmPosStn.setComments("小车取料完成!");
        frmPosStn.setUpdateDate(new Date());
        stnMappingService.updateById(frmPosStn);
//        向PLC写入取料完成causeBy:Column 'cont_no' cannot be null;
        pcItemService.updateValueByNo(curStn.getTargetGet(), "1");
        msg = msg + "取料完成[" + curStn.getTargetGet() + "]写入信号[1]!";

        wcsTrk.setComments(msg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
        task.setStatus(RcsConstants.HK_STATUS_TAKE); //取料完成不停止,直接搬走
        task.setData("LoadDone");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 放料申请
     * @param task
     */
    private void agvTrkUnload(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-放料申请]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkUnload";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[UnloadRequest]申请!";
//        获取安全交互卡控点(Arrived对应外卡控站点)
        StnMappingEntity extStn = stnMappingService.getStnByNo(positionCode);
        if (extStn == null) {
//            站点未配置
            code = "ArrivedError_001";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        匹配主任务（主要是看任务中的空满标记）
        TrkEntity wcsTrk = trkService.selectById(task.getTrkId());
        if (wcsTrk == null) {
//            站点未配置
            code = "ArrivedError_002";
            msg = msg + "无关联主任务!ID为[" + task.getTrkId() + "]!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        申请进入
        pcItemService.updateValueByNo(extStn.getTargetAgv(), "1");
        msg = msg + "放料申请[" + extStn.getTargetAgv() + "]写入信号[1]!";
        wcsTrk.setCurPos(positionCode);
        wcsTrk.setComments(msg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
        task.setStatus(RcsConstants.HK_STATUS_UNLOAD); //任务状态
        task.setData("UnloadRequest");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * AGV-UNLOAD申请(放料完成)
     * @param task
     */
    private void agvTrkUnLoadDone(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-下料完成]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkUnLoadDone";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[UnloadDone]申请!";

        //        匹配主任务
        TrkEntity wcsTrk = trkService.selectById(task.getTrkId());
        if (wcsTrk == null) {
//            站点未配置
            code = "UnloadDone_002";
            msg = msg + "无关联主任务!ID为[" + task.getTrkId() + "]!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        根据当前位置获取一下站台对应的站点(内卡控)
        StnMappingEntity curStn = stnMappingService.getStnByNo(positionCode);
        if (curStn == null) {
            code = "UnloadDone_001";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        //        向PLC写入放料完成
        pcItemService.updateValueByNo(curStn.getTargetPut(), "1");
        msg = msg + "放料完成[" + curStn.getTargetPut() + "]写入信号[1]!";
        wcsTrk.setComments(msg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
        task.setStatus(RcsConstants.HK_STATUS_TAKE); //任务状态
        task.setData("UnloadDone");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 申请打包
     * @param task
     */
    private void agvTrkApplyPackage(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-申请打包]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyPackage";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[PackageRequest]申请!";

        //匹配主任务
        TrkEntity wcsTrk = trkService.selectById(task.getTrkId());
        if (wcsTrk == null) {
            //站点未配置
            code = "PackageError_002";
            msg = msg + "无关联主任务!ID为[" + task.getTrkId() + "]!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        //获取当前站点对应的机台编号
        StnMappingEntity extStn = stnMappingService.getStnByNo(positionCode);
        if (extStn == null) {
            //站点未配置
            code = "PackageError_001";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
//        与工位光栅进行安全交互(向pc_item表中写入对应工位 1-申请打包)
        pcItemService.updateValueByNo(extStn.getTargetAgv(), "1");
        msg = msg + "打包申请[" + extStn.getTargetAgv() + "]写入信号[1]!";
        wcsTrk.setComments(msg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
//        更新任务状态
        task.setStatus(RcsConstants.HK_STATUS_PACKAGE_REQ); //任务状态
        task.setData("PackageRequest");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 打包等待
     * @param task
     */
    private void agvTrkApplyPackageWait(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-打包等待]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkApplyPackageWait";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "[" + task.getAgvCode() + "]号车在[" + positionCode + "]进行[PackageWaiting]申请!";

        //匹配主任务
        TrkEntity wcsTrk = trkService.selectById(task.getTrkId());
        if (wcsTrk == null) {
            //站点未配置
            code = "LoadError_002";
            msg = msg + "无关联主任务!ID为[" + task.getTrkId() + "]!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        //获取当前站点对应的机台编号
        StnMappingEntity curStn = stnMappingService.getStnByNo(positionCode);
        if (curStn == null) {
            //站点未配置
            code = "LoadError_001";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }

        //        向PLC写入放料完成
        pcItemService.updateValueByNo(curStn.getTargetPut(), "1");
        msg = msg + "放料完成[" + curStn.getTargetPut() + "]写入信号[1]!";

//        将托盘信息写入打包工位
        curStn.setStatus(2);
        curStn.setContNo(task.getCtnrCode());
        curStn.setComments("小车完成放料");
        curStn.setUpdateDate(new Date());
        stnMappingService.updateById(curStn);

        wcsTrk.setComments(msg);
        wcsTrk.setUpdateDate(new Date());
        trkService.updateById(wcsTrk);
//        更新任务状态
        task.setStatus(RcsConstants.HK_STATUS_PACKAGE_WAIT); //任务状态
        task.setData("PackageWaiting");
        task.setUpdateDate(new Date());
        hkService.updateById(task);
//        记录日志
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }

    /***
     * 任务结束(将对应agv搬送任务完成并转移历史)
     * @param task
     */
    private void agvTrkEnd(AgvTrkHkEntity task, String positionCode) {
        String workName = "[流程-任务结束]-HK";
        String workProc = "AgvCallbackHkServiceImpl.agvTrkEnd";
        String code = WcsConstants.PROC_CODE_SUCCESS;
        String msg = "小车[" + task.getAgvCode() + "]到达站点[" + positionCode + "],任务完成[End]通知!";

//      获取[wcs_trk]信息
        task.setStatus(RcsConstants.HK_STATUS_END); //任务完成
        task.setData("End!");
        task.setCurrentPositionCode(positionCode);
        task.setUpdateDate(new Date());
        hkService.updateById(task);
        TrkEntity trkEntity = trkService.selectById(task.getTrkId());
        if (trkEntity == null) {
            return;
        }

//        放料完成更新当前站点的
        StnMappingEntity curStn = stnMappingService.getStnByNo(positionCode);
        StnMappingEntity toPosStn = stnMappingService.getStnByNo(trkEntity.getToPos());
        if (curStn == null) {
            //站点未配置
            code = "LoadError_001";
            msg = msg + "站点[" + positionCode + "]未配置!";
            logWorkService.workLogging(workName, task.getTaskCode(), code,
                    msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
            return;
        }
        //        将完成信号写入PLC(任务完成一定是放料,PC_FINISH_PUT)
        if (ObjectUtils.isNotEmpty(curStn.getTargetPut())) {
            pcItemService.updateValueByNo(curStn.getTargetPut(), "1");
        }
//        PcItemEntity itemByStn = pcItemService.getPcItemByStn(positionCode, "PC_FINISH_PUT");
//        if (itemByStn != null) {
//            pcItemService.updateValueByNo(itemByStn.getItemNo(), "1");
//        }

        toPosStn.setStatus(2);
        toPosStn.setContNo(task.getCtnrCode());
        toPosStn.setUpdateDate(new Date());
        stnMappingService.updateById(toPosStn);

        //如果是线尾-打包区的任务，就立即生成下一条任务
        if (task.getTaskTyp().equals("CQC31")) {

            RouteSetEntity routeSetByPath = routeSetService.getRouteSetByCarry(trkEntity.getCarryNo());
            String reqCode = trkEntity.getCarryNo() + System.currentTimeMillis();
            String taskCode = String.valueOf(System.currentTimeMillis());

            AgvTrkHkEntity agvTrkHkNew = new AgvTrkHkEntity();
            agvTrkHkNew.setTrkId(task.getTrkId());
            agvTrkHkNew.setPriority(WcsConstants.TRK_PRTY_DEF);
            agvTrkHkNew.setReqCode(reqCode);
            agvTrkHkNew.setTaskCode(taskCode);
            agvTrkHkNew.setTaskTyp("CQC32");
            agvTrkHkNew.setPositionCode(routeSetByPath.getNextPos());
            agvTrkHkNew.setPositionType(task.getPositionType());
            agvTrkHkNew.setCtnrCode(task.getCtnrCode());
            agvTrkHkNew.setCtnrTyp("2");
            agvTrkHkNew.setTaskMode("0");
            agvTrkHkNew.setAgvCode("14");
            agvTrkHkNew.setCreator(WcsConstants.WCS_USER_ID);
            agvTrkHkDao.insert(agvTrkHkNew);
        } else {
            trkEntity.setTrkSt(WcsConstants.TRK_STATUS_DONE);
            trkEntity.setComments(msg);
            trkEntity.setCurPos(positionCode);
            trkEntity.setUpdater(WcsConstants.WCS_USER_ID);
            trkEntity.setUpdateDate(new Date());
            trkService.updateById(trkEntity);
        }

//        将AGV任务转移历史
//        hkService.updateAgvTrkByTaskCode(task.getTaskCode());
//        将TRK数据也进行转移
//        trkService.updateTrkByContNo(trkEntity.getContNo());
        logWorkService.workLogging(workName, task.getTaskCode(), code,
                msg, null, workProc, WcsConstants.WCS_USER_NAME, 10L);
    }
}
